package com.seeyon.apps.kkSample.manager.impl;

import com.alibaba.fastjson.JSONObject;
import com.seeyon.apps.collaboration.manager.ColManager;
import com.seeyon.apps.collaboration.po.ColSummary;
import com.seeyon.apps.kkSample.config.KKESignConfig;
import com.seeyon.apps.kkSample.enums.LogsFormEnum;
import com.seeyon.apps.kkSample.enums.UnComplyInfoEnum;
import com.seeyon.apps.kkSample.manager.KKEsignContractFileSignManager;
import com.seeyon.apps.kkSample.manager.KKEsignTemplateFileManager;
import com.seeyon.apps.kkSample.po.SHKKResult;
import com.seeyon.apps.kkSample.utils.cap4.Cap4FormUtil;
import com.seeyon.apps.kkSample.utils.http.HttpUtil;
import com.seeyon.apps.kkSample.utils.jdbc.JDBCAgentUtil;
import com.seeyon.cap4.form.bean.FormBean;
import com.seeyon.cap4.form.bean.FormDataMasterBean;
import com.seeyon.cap4.form.bean.FormFieldBean;
import com.seeyon.cap4.form.service.CAP4FormManager;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.ctpenumnew.manager.EnumManager;
import com.seeyon.ctp.common.exceptions.BusinessException;
import com.seeyon.ctp.common.filemanager.manager.AttachmentManager;
import com.seeyon.ctp.common.filemanager.manager.FileManager;
import com.seeyon.ctp.common.log.CtpLogFactory;
import com.seeyon.ctp.common.po.ctpenumnew.CtpEnumItem;
import com.seeyon.ctp.common.po.filemanager.Attachment;
import com.seeyon.ctp.common.po.filemanager.V3XFile;
import com.seeyon.ctp.organization.bo.V3xOrgMember;
import com.seeyon.ctp.organization.manager.OrgManager;
import com.seeyon.ctp.services.CTPLocator;
import com.seeyon.ctp.util.DateUtil;
import com.seeyon.ctp.util.json.JSONUtil;
import com.seeyon.v3x.services.form.FormFactory;
import com.seeyon.v3x.services.form.bean.FormExport;
import com.seeyon.v3x.services.form.bean.ValueExport;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;

import java.io.File;
import java.util.*;

public class KKEsignManagerImpl implements com.seeyon.apps.kkSample.manager.KKEsignManager {

    private static final Log LOG = CtpLogFactory.getLog(KKEsignManagerImpl.class);
    private static final FileManager fileManager = (FileManager) AppContext.getBean("fileManager");
    private static final AttachmentManager attachmentManager = (AttachmentManager) AppContext.getBean("attachmentManager");
    private String appUrl;
    private String appId;
    private String secret;
    private String upFile;
    private String unTmpCode;
    private String OAurl;
    private final ColManager colManager = (ColManager) AppContext.getBean("colManager");
    private final OrgManager orgManager = (OrgManager) AppContext.getBean("orgManager");
    private final CAP4FormManager cap4FormManager = (CAP4FormManager) AppContext.getBean("cap4FormManager");
    private final KKEsignContractFileSignManager kkESignContractFileSignManager = (KKEsignContractFileSignManager) AppContext.getBean("kkESignContractFileSignManager");
    private final KKEsignTemplateFileManager kkEsignFileTemplateManager = (KKEsignTemplateFileManager) AppContext.getBean("kkEsignFileTemplateManager");

    /**
     * e签宝 - 发起签署
     *
     * @param formBean
     * @param formDataMasterBean
     * @return
     */
    @Override
    public Map<String, Object> doSignature(FormBean formBean, FormDataMasterBean formDataMasterBean) {
        Map<String, Object> returnMap = new HashMap<>();
        //获取应用配置信息
        HashMap<String, Object> unComplyInfo = (HashMap<String, Object>) getUnComplyInfo();

        this.appUrl = unComplyInfo.get(UnComplyInfoEnum.appUrl.getFiledName()).toString();
        this.appId = unComplyInfo.get(UnComplyInfoEnum.appID.getFiledName()).toString();
        this.secret = unComplyInfo.get(UnComplyInfoEnum.secret.getFiledName()).toString();
        this.upFile = unComplyInfo.get(UnComplyInfoEnum.upFile.getFiledName()).toString();
        this.unTmpCode = unComplyInfo.get(UnComplyInfoEnum.unTmpCode.getFiledName()).toString();
        this.OAurl = unComplyInfo.get(UnComplyInfoEnum.OAurl.getFiledName()).toString();
        //获取token
        String token = getToken(this.appUrl, this.appId, this.secret);
        //请求头参数
        HashMap<String, Object> headerParams = new HashMap<>();
        headerParams.put(UnComplyInfoEnum.appID.getFiledName(), appId);
        headerParams.put(UnComplyInfoEnum.token.getFiledName(), token);
        headerParams.put(UnComplyInfoEnum.contentType.getFiledName(), UnComplyInfoEnum.contentType.getFiledShowValue());

        /**
         * 查询日志表，判断签署流程是否发起
         */
        Map<String, Object> sqlParam = new HashMap<>();
        List<Map> logList = new ArrayList<Map>();
        try {
            FormBean unFormBean = cap4FormManager.getFormByFormCode(this.unTmpCode);
            //查询底表 是否存在流程数据ID
            sqlParam.put("=|" + LogsFormEnum.dataId.getFiledShowValue() + "|" + LogsFormEnum.dataId.getFiledName(), formDataMasterBean.getId().toString());
            logList = JDBCAgentUtil.doCap4FormQuery(unFormBean.getMasterTableBean(), sqlParam);
        } catch (BusinessException e) {
            LOG.error("查询日志底表失败" + e.getMessage(), e);
        }
        //如果日志表中没有信息，则发起签署
        if (logList.isEmpty()) {
            if (Cap4FormUtil.getFieldValue(this.upFile, formDataMasterBean) != null) {
                Long subReference = Long.valueOf(Cap4FormUtil.getFieldValue(this.upFile, formDataMasterBean).toString());
                /**
                 * 下载A8附件并上传到e签宝
                 */
                Map<String, Object> uploadFileResult = uploadFile(Long.valueOf(subReference.toString()), headerParams, appUrl);
                if (uploadFileResult.get("code").toString().equals("0")) {
                    ArrayList<String> fileIdList = (ArrayList<String>) uploadFileResult.get("fileIdList");
                    LOG.info("签署附件集合：" + JSONUtil.toJSONString(fileIdList));
                    /**
                     * 程序休眠1秒
                     */
                    while (true) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            LOG.info("程序休眠" + e.getMessage(), e);
                        }
                        /**
                         * 轮询文件上传状态
                         */
                        Boolean flag = false;
                        for (int i = 0; i < fileIdList.size(); i++) {
                            SHKKResult fileType = kkEsignFileTemplateManager.getFileType(this.appUrl, headerParams, fileIdList.get(i));
                            LOG.info("文件上传状态：" + JSONUtil.toJSONString(fileType));
                            if (fileType.getCode() == 0) {
                                if (Integer.valueOf(String.valueOf(fileType.getData().get("fileStatus"))) == 2 || Integer.valueOf(String.valueOf(fileType.getData().get("fileStatus"))) == 5) {
                                    flag = true;
                                } else {
                                    flag = false;
                                    break;
                                }
                            }
                        }
                        if (flag) {
                            break;
                        }
                    }

                    /**
                     * 基于文件发起签署
                     */
                    SHKKResult createByFileResult = kkESignContractFileSignManager.createByFile(fileIdList, formBean, formDataMasterBean, this.appUrl, this.OAurl, headerParams);
                    LOG.info("基于文件发起签署结果：" + JSONUtil.toJSONString(createByFileResult));

                    if (Objects.isNull(createByFileResult)) {
                        LOG.info("基于文件发起签署失败");
                        returnMap.put("code", 500);
                        returnMap.put("message", "文件发起签署错误");
                        return returnMap;
                    }
                    if (createByFileResult.getCode() == 0) {
                        LOG.info("基于文件发起签署成功 - 签署流程Id：" + createByFileResult.getData().get("signFlowId"));
                        String psnAccount = null;

                        String qsfsjh = String.valueOf(Cap4FormUtil.getFieldValue("手机号码", formDataMasterBean));
                        if (StringUtils.isNotBlank(qsfsjh)) {
                            psnAccount = qsfsjh;
                        }

//                        FormTableBean formSonTableBean = formBean.getFormTableBeanByFieldName(formBean.getFieldBeanByDisplay("电子签个人名称").getName());
//                        List<FormDataSubBean> formDataSubBeans = formDataMasterBean.getSubData(formSonTableBean.getTableName());
//                        //TODO 获取签署人手机号
//                        for (FormDataSubBean formDataSubBean : formDataSubBeans) {
//                            String qslx = getEnumValue(Long.valueOf(String.valueOf(formDataSubBean.getFieldValue(formBean.getFieldBeanByDisplay("相对方").getName()))));
//                            if(Objects.equals(qslx,"甲方")){
//                                psnAccount = (String) formDataSubBean.getFieldValue(formBean.getFieldBeanByDisplay("电子签手机号码").getName());
//                            }
//                        }

                        SHKKResult signUrResult = kkESignContractFileSignManager.signUrl(appUrl, headerParams, createByFileResult.getData().get("signFlowId").toString(), psnAccount);
                        LOG.info("获取签署连接：" + signUrResult);
                        /**
                         * 新增日志底表
                         */
                        ColSummary colSummary = null;
                        try {
                            colSummary = colManager.getColSummaryByFormRecordId(formDataMasterBean.getId());
                        } catch (BusinessException e) {
                            LOG.info("获取流程对象异常");
                            returnMap.put("code", "-1");
                            returnMap.put("message", "获取流程对象异常");
                            return returnMap;
                        }
                        Map<String, Object> logsMap = new HashMap<String, Object>();
                        logsMap.put(LogsFormEnum.dataId.getFiledShowValue(), formDataMasterBean.getId().toString());//数据ID
                        logsMap.put(LogsFormEnum.serialNumber.getFiledShowValue(), Cap4FormUtil.getFieldValue(LogsFormEnum.serialNumber.getFiledShowValue(), formDataMasterBean));//流水号
                        logsMap.put(LogsFormEnum.thirdFileId.getFiledShowValue(), fileIdList);//附件ID
                        logsMap.put(LogsFormEnum.status.getFiledShowValue(), "未签署");//签署状态
                        logsMap.put(LogsFormEnum.thirdId.getFiledShowValue(), createByFileResult.getData().get("signFlowId"));//三方主键:签署流程id
                        logsMap.put(LogsFormEnum.flowId.getFiledShowValue(), colSummary.getId());//流程ID
                        logsMap.put(LogsFormEnum.title.getFiledShowValue(), colSummary.getSubject());//标题
                        logsMap.put(LogsFormEnum.updateTime.getFiledShowValue(), DateUtil.currentDate());//更新时间
                        createLogs(this.unTmpCode, logsMap);
                        returnMap.put("code", signUrResult.getCode());
                        returnMap.put("message", signUrResult.getMessage());
                        returnMap.put("data", signUrResult.getData());
                        return returnMap;
                    } else {
                        LOG.info("基于文件发起签署失败");
                        returnMap.put("code", createByFileResult.getCode());
                        returnMap.put("message", createByFileResult.getMessage());
                        return returnMap;
                    }
                } else {
                    return uploadFileResult;
                }
            }
        } else {
            returnMap.put("code", -1);
            returnMap.put("message", "签署流程已经发起");
            return returnMap;
        }
        return null;
    }

    /**
     * 获得下拉选项对应的值
     *
     * @param enumId
     * @return
     */
    public String getEnumValue(Long enumId) {
        EnumManager enumManager = (EnumManager) AppContext.getBean("enumManagerNew");
        CtpEnumItem ctpEnumItem = enumManager.getEnumItem(enumId);
        return ctpEnumItem.getShowvalue();
    }

    /**
     * 获取token
     *
     * @param appUrl
     * @param appId
     * @param secret
     * @return
     */
    @Override
    public String getToken(String appUrl, String appId, String secret) {
        String url = appUrl + "/v1/oauth2/access_token?appId=" + appId + "&secret=" + secret + "&grantType=client_credentials";
        SHKKResult result = JSONObject.parseObject(HttpUtil.getMethod(url), SHKKResult.class);
        if (result != null) {
            if (result.getCode() == 0) {
                String token = MapUtils.getString(result.getData(), "token");
                LOG.info("e签宝获取到token：" + token);
                return token;
            }
        }
        return null;
    }

    /**
     * 下载A8附件并上传到e签宝
     *
     * @param subReference 表单次数据id
     * @param headerParams 请求头参数
     * @param appUrl       e签宝集成地址
     * @return
     */
    @Override
    public Map<String, Object> uploadFile(Long subReference, Map<String, Object> headerParams, String appUrl) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        List<String> fileIdList = new ArrayList<String>();//带签署文件集合
        List<Long> attachmentList = attachmentManager.getBySubReference(subReference);
        for (int i = 0; i < attachmentList.size(); i++) {
            try {
                Long attId = attachmentList.get(i);
                Attachment attach = new Attachment();
                attach = attachmentManager.getAttachmentByFileURL(attId);
                Long fileUrl = attach.getFileUrl();
                V3XFile v3xFile = fileManager.getV3XFile(fileUrl);
                Long size = v3xFile.getSize();
                String fileName = v3xFile.getFilename();
                String prefix = fileName.substring(fileName.lastIndexOf(".") + 1);// 后缀名
//                if(!"pdf".equals(prefix.toLowerCase())){//只支持 PDF 文件
//                    resultMap.put("code", -1);
//                    resultMap.put("message", "请上传 pdf 文件!");
//                    resultMap.put("fileIdList", fileIdList);
//                    return resultMap;
//                }
                File file = fileManager.getFile(v3xFile.getId(), v3xFile.getCreateDate());
                //获取文件上传地址
                SHKKResult result = kkEsignFileTemplateManager.getFileUpLoadUrl(appUrl, headerParams, file, file.getName(), size);
                if (result.getCode() == 0) {
                    String fileUpLoadUrl = result.getData().get("fileUploadUrl").toString();
                    //上传文件流
                    String errCode = kkEsignFileTemplateManager.upLoad(file, fileUpLoadUrl);
                    if (errCode.equals("0")) {
                        fileIdList.add(result.getData().get("fileId").toString());

                    } else {
                        resultMap.put("code", -1);
                        resultMap.put("message", "上传文件流失败");
                        resultMap.put("fileIdList", fileIdList);
                        return resultMap;
                    }
                } else {
                    resultMap.put("code", -1);
                    resultMap.put("message", result.getMessage());
                    resultMap.put("fileIdList", fileIdList);
                    return resultMap;
                }
            } catch (BusinessException e) {
                resultMap.put("code", -1);
                resultMap.put("message", "获取OA文件异常");
                resultMap.put("fileIdList", fileIdList);
                return resultMap;
            }
        }
        resultMap.put("code", 0);
        resultMap.put("message", "下载A8附件并上传e签宝成功");
        resultMap.put("fileIdList", fileIdList);
        return resultMap;
    }

    /**
     * 获取应用配置信息
     *
     * @return
     */
    @Override
    public Map getUnComplyInfo() {
        try {
            FormBean formBean = cap4FormManager.getFormByFormCode(KKESignConfig.UNCOMPLYCODE);
            Map<String, Object> param = new HashMap<>();
            List<Map> unComplyInfoList = JDBCAgentUtil.doCap4FormQuery(formBean.getMasterTableBean(), param);
            Map<String, Object> unComplyInfoMap = unComplyInfoList.get(0);
            Map<String, Object> returnMap1 = new HashMap<String, Object>();
            for (String key : unComplyInfoMap.keySet()) {
                FormFieldBean formFieldBean = formBean.getFieldBeanByName(key);//根据控件的字段名
                if (formFieldBean != null) {
                    returnMap1.put(formFieldBean.getDisplay(), unComplyInfoMap.get(key));
                }
            }
            Map<String, Object> returnMap2 = new HashMap<String, Object>();
            returnMap2.put(UnComplyInfoEnum.appID.getFiledName(), returnMap1.get(UnComplyInfoEnum.appID.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.secret.getFiledName(), returnMap1.get(UnComplyInfoEnum.secret.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.appUrl.getFiledName(), returnMap1.get(UnComplyInfoEnum.appUrl.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.unTmpCode.getFiledName(), returnMap1.get(UnComplyInfoEnum.unTmpCode.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.upFile.getFiledName(), returnMap1.get(UnComplyInfoEnum.upFile.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.OAurl.getFiledName(), returnMap1.get(UnComplyInfoEnum.OAurl.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.downFile.getFiledName(), returnMap1.get(UnComplyInfoEnum.downFile.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.type.getFiledName(), returnMap1.get(UnComplyInfoEnum.type.getFiledShowValue()));
            returnMap2.put(UnComplyInfoEnum.key.getFiledName(), returnMap1.get(UnComplyInfoEnum.key.getFiledShowValue()));
            return returnMap2;
        } catch (Exception e) {
            LOG.error("获取应用配置信息异常：" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 日志底表新增数据
     *
     * @param tmpCode 底表模板编号
     * @param logsMap 需要写入底表值Map
     */
    public void createLogs(String tmpCode, Map<String, Object> logsMap) {
        if (StringUtils.isNotBlank(tmpCode) && logsMap != null && !logsMap.isEmpty()) {
            try {
                FormBean formBean = cap4FormManager.getFormByFormCode(tmpCode);
                if (formBean != null) {
                    V3xOrgMember v3xOrgMember = orgManager.getMemberById(formBean.getCreatorId());
                    String loginName = v3xOrgMember.getLoginName();
                    //新增底表数据
                    FormFactory formFactory = CTPLocator.getInstance().lookup(FormFactory.class); //FormFactory表单工厂对象
                    FormExport formExport = new FormExport();//表单数据对象
                    List<ValueExport> mainValues = new ArrayList<ValueExport>();
                    mainValues.add(setValue(LogsFormEnum.serialNumber.getFiledShowValue(), logsMap.get(LogsFormEnum.serialNumber.getFiledShowValue()) + ""));//流水号
                    mainValues.add(setValue(LogsFormEnum.title.getFiledShowValue(), logsMap.get(LogsFormEnum.title.getFiledShowValue()) + ""));//标题
                    mainValues.add(setValue(LogsFormEnum.flowId.getFiledShowValue(), logsMap.get(LogsFormEnum.flowId.getFiledShowValue()) + ""));//流程id
                    mainValues.add(setValue(LogsFormEnum.thirdFileId.getFiledShowValue(), logsMap.get(LogsFormEnum.thirdFileId.getFiledShowValue()) + ""));//附件id
                    mainValues.add(setValue(LogsFormEnum.status.getFiledShowValue(), logsMap.get(LogsFormEnum.status.getFiledShowValue()) + ""));//状态
                    mainValues.add(setValue(LogsFormEnum.thirdId.getFiledShowValue(), logsMap.get(LogsFormEnum.thirdId.getFiledShowValue()) + ""));//第三方主键
                    mainValues.add(setValue(LogsFormEnum.updateTime.getFiledShowValue(), logsMap.get(LogsFormEnum.updateTime.getFiledShowValue()) + ""));//更新时间
                    mainValues.add(setValue(LogsFormEnum.dataId.getFiledShowValue(), logsMap.get(LogsFormEnum.dataId.getFiledShowValue()) + ""));//数据id
                    formExport.setValues(mainValues);
                    Map<String, Object> attachmentMountMap = new HashMap<>();//附件
                    String[] condition = {LogsFormEnum.dataId.getFiledShowValue()};//唯一标识:数据id
                    long masterId = formFactory.importBusinessForm(AppContext.getCurrentUser().getLoginName(), tmpCode, formExport, condition, attachmentMountMap);
                    LOG.info("新增日志底表成功");
                }
            } catch (Exception e) {
                LOG.error("新增日志底表数据异常" + e.getMessage(), e);
            }
        } else {
            LOG.error("新增日志底表数据失败");
        }
    }

    private ValueExport setValue(String displayName, String value) {
        ValueExport valueExport = new ValueExport();
        valueExport.setDisplayName(displayName);
        valueExport.setValue(value);
        return valueExport;
    }
}
